package com.fdb.efp.nls.service.impl.sed.repay;

import com.alibaba.fastjson.JSON;
import com.fdb.efp.nls.service.facade.NlsApplyInfoService;
import com.fdb.efp.nls.service.vo.NlsApplyInfoVO;
import com.fdb.efp.nls.service.vo.queue.NlsProcessBizVO;
import com.fdb.basic.framework.core.constant.EsbEnums;
import com.fdb.basic.framework.core.constant.SDicToExternalConstant;
import com.fdb.basic.framework.core.exception.BizException;
import com.fdb.basic.framework.core.exception.ExternalSysException;
import com.fdb.basic.framework.core.exception.OcmSystemException;
import com.fdb.basic.framework.core.util.DateUtility;
import com.fdb.basic.framework.core.util.StringUtil;
import com.fdb.basic.framework.core.util.TimeUtil;
import com.fdb.basic.framework.core.util.sdic.SDicToExternal;
import com.fdb.efp.esb.common.constant.EsbBizEnums;
import com.fdb.efp.esb.service.bo.req.sed.repay.ReqLoanAccountBean;
import com.fdb.efp.esb.service.bo.req.sed.repay.ReqLoanRepayBean;
import com.fdb.efp.esb.service.bo.req.sed.repay.ReqLoanRepayResultQryBean;
import com.fdb.efp.esb.service.bo.resp.sed.repay.RespLoanRepayBean;
import com.fdb.efp.esb.service.bo.resp.sed.repay.RespLoanRepayResultQryBean;
import com.fdb.efp.esb.service.facade.sed.repay.LoanRepayResultQryService;
import com.fdb.efp.esb.service.facade.sed.repay.LoanRepayService;
import com.fdb.efp.limit.service.facade.LmtPrdContService;
import com.fdb.efp.limit.service.vo.LmtPrdContVO;
import com.fdb.efp.nls.service.facade.AccLoanService;
import com.fdb.efp.nls.service.facade.LoanRepayDetailService;
import com.fdb.efp.nls.service.vo.AccLoanVO;
import com.fdb.efp.loan.service.vo.LoanRepayDetailVO;
import com.fdb.efp.nls.common.constant.NlsApplyInfoEnums;
import com.fdb.efp.nls.common.constant.sed.DealState;
import com.fdb.efp.nls.common.constant.sed.SedNlsEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 需求编号：【2019D0519】（业务提的需求编号）
 * 问题编号：【xxxxxxx】（若不是因为修复问题而新增该类，则留空）
 * 开发人员：qiuyf
 * 创建日期：2019年5月14日 下午2:33:18
 * 功能描述：还款申请校验插槽
 */
@Service("repayApplJudgeService")
public class RepayApplJudgeServiceImpl extends RepaySoltServiceImpl {

	private static final Logger logger = LoggerFactory.getLogger(RepayApplJudgeServiceImpl.class);
	
	@Override
	public void doExecute(NlsProcessBizVO nlsProcessBizVo, LoanRepayDetailVO loanRepayDetailVO) throws Exception {
		String setlSeq = loanRepayDetailVO.getSetlSeq();
		String billNo = loanRepayDetailVO.getLoanNo();
		logger.info("======>还款申请准入服务开始,流水号为:"+setlSeq+"<======");
		try {
			/* 判断是否是成功还款后的系统内部异常处理 */
			if(SedNlsEnum.ExceptionLocation.REPAY_SUCCESS_AFTER_EXCEPTION.getValue().equals(loanRepayDetailVO.getExceptionLocation())) {
				AccLoanVO accLoanVO = new AccLoanVO();
				accLoanVO.setBillNo(billNo);
				accLoanVO = accLoanService.queryByPk(accLoanVO);
				if(Objects.isNull(accLoanVO)) {
					throw new OcmSystemException(SedNlsEnum.ExceptionLocation.REPAY_SUCCESS_AFTER_EXCEPTION.getValue(), "还款成功后，根据借据号【" + billNo + "】，获取到的借据信息为空！");
				}
				this.updStateAndLmt(loanRepayDetailVO, accLoanVO);
			}
			else {
				this.excuteRepayMain(loanRepayDetailVO);
			}
		} catch (Exception e) {
			logger.error(Arrays.toString(e.getStackTrace()));
			nlsProcessBizVo.setExceptionFlag(true);
			nlsProcessBizVo.setExceptionMsg(e);
		} finally {
			logger.info("======>还款申请准入服务结束,流水号为:"+setlSeq+"<======");
		}
	}
	
	/**
	 * 还款主流程处理
	 * @author  qiuyf
	 * @since 2019年6月27日 下午9:17:17
	 * @version 0.1 初始为0.1,后续变更则修改
	 */
	private void excuteRepayMain(LoanRepayDetailVO loanRepayDetailVO) throws Exception {
		String setlSeq = loanRepayDetailVO.getSetlSeq();
		String globalSerno = loanRepayDetailVO.getGlobalSerno();
		String billNo = loanRepayDetailVO.getLoanNo();
		// 根据提前还款申请传送过来的全局流水号，调用贷款回收结果查询
		logger.info("根据全局流水号【" + globalSerno + "】，调用贷款还款结果查询接口开始-----------------------------------");
		ReqLoanRepayResultQryBean reqLoanRepResQryBean = new ReqLoanRepayResultQryBean();
		reqLoanRepResQryBean.setTxnGlblSrlNo(globalSerno);
		RespLoanRepayResultQryBean respLoanRepResQryBean = new RespLoanRepayResultQryBean();
		try {
			respLoanRepResQryBean = loanRepayResultQryService.loanRepayResultQry(reqLoanRepResQryBean); 
		} catch (Exception e) {
			throw new ExternalSysException(e.getMessage());
		}
		logger.info("根据全局流水号【" + globalSerno + "】，调用贷款还款结果查询接口结束-------返回结果为："+JSON.toJSONString(respLoanRepResQryBean));

		//通过借据号获取借据信息
		AccLoanVO accLoanVO = this.getAccLoan(billNo);

		String isRepay = respLoanRepResQryBean.getQrySt();
		if(SedNlsEnum.QuerySts.WITHOUT.getValue().equals(isRepay)) {
			/* 执行还款  */
			this.excuteRepay(loanRepayDetailVO, accLoanVO);
		}else if(SedNlsEnum.QuerySts.HAVE.getValue().equals(isRepay)) {
			//交易状态
			String dealState = respLoanRepResQryBean.getTxnStCd();
			if(DealState.DEALING.getValue().equals(dealState)) {
				throw new ExternalSysException("还款申请流水号【 " + setlSeq + "】，全局流水号【" + globalSerno +"】，存在处理中的还款申请！");
			}
			else if(DealState.UNKNOW.getValue().equals(dealState)) {
				throw new ExternalSysException("还款申请流水号【 " + setlSeq + "】，全局流水号【" + globalSerno +"】，存在未知状态的还款申请！");
			}
			else if(DealState.SUSPEND.getValue().equals(dealState)) {
				// @date 2019/07/17
				throw new ExternalSysException("还款申请流水号【 " + setlSeq + "】，全局流水号【" + globalSerno +"】，存在待处理【互金已接收到还款信息，待处理】状态的还款申请！");
			}
			else if(DealState.FAIL.getValue().equals(dealState)) {
				throw new Exception("还款申请流水号【 " + setlSeq + "】，全局流水号【 " + globalSerno + "】，还款失败！异常信息:"+loanRepayDetailVO.getExceptionMsg());
			}
			else if(DealState.SUCCESS.getValue().equals(dealState)) {
				this.updStateAndLmt(loanRepayDetailVO, accLoanVO);
			}else {
				throw new ExternalSysException("调用互金贷款还款结果查询接口【30230007_01】，返回的交易状态不合规，值为："+dealState);
			}
		}else {
			throw new ExternalSysException("调用互金贷款还款结果查询接口【30230007_01】，返回的查询状态不合规，值为："+isRepay);
		}
	}
	
	private AccLoanVO getAccLoan(String billNo) throws BizException {
		AccLoanVO accLoanVO = new AccLoanVO();
		accLoanVO.setBillNo(billNo);
		accLoanVO = accLoanService.queryByPk(accLoanVO);
		if(Objects.isNull(accLoanVO)) {
			throw new BizException("调用贷款回收接口前，根据借据号【" + billNo + "】，获取到的借据信息为空！");
		}
		return accLoanVO;
	}

	/**
	 * 组装还款接口请求报文
	 * @author  qiuyf
	 * @since 2019年5月14日 下午3:11:46
	 * @version 0.1 初始为0.1,后续变更则修改
	 */
	private ReqLoanRepayBean buildReqLoanRepayBean(LoanRepayDetailVO loanRepayDetailVO, AccLoanVO accLoanVO) throws Exception {

		ReqLoanRepayBean reqLoanRepayBean = new ReqLoanRepayBean();
		//贷款号
		reqLoanRepayBean.setLoanNo(accLoanVO.getLoanSeq());
		//发放号
		reqLoanRepayBean.setDistrNo(accLoanVO.getDistrNo());
		//还款日期
		reqLoanRepayBean.setRpyDt(StringUtil.isNotEmpty(loanRepayDetailVO.getSetlApplyDt()) ? DateUtility.format10To8(loanRepayDetailVO.getSetlApplyDt()) : null);
		//还款类型
		try {
			reqLoanRepayBean.setRpyType(SDicToExternal.getExternalSysDicVal(SDicToExternalConstant.SYSID_IFP, SDicToExternalConstant.SETL_TYP, loanRepayDetailVO.getSetlTyp()));
		} catch (Exception e) {
			logger.error("还款类型字典项类型转换异常！", e);
			throw new Exception("调用贷款回收接口组装请求报文时，出现还款类型字典项转换异常！");
		}
		//还款金额
		reqLoanRepayBean.setRpyAmt(loanRepayDetailVO.getTotalAmt() == null ? BigDecimal.ZERO.toString() : loanRepayDetailVO.getTotalAmt().toString());
		//还款本金
		reqLoanRepayBean.setRpyPrin(loanRepayDetailVO.getSetlOdPrcpAmt() == null ? BigDecimal.ZERO.toString() : loanRepayDetailVO.getSetlOdPrcpAmt().toString());
		//还款期次
		reqLoanRepayBean.setRpyTime(loanRepayDetailVO.getRepayTerm());
		//还款原因
		reqLoanRepayBean.setRpyRsn(loanRepayDetailVO.getRepayReason());

		//结算信息数组----------------- 组装 start ------------------------------------------------
		List<ReqLoanAccountBean> reqLoanAccountList = new ArrayList<ReqLoanAccountBean>();
		if(StringUtil.isStrNotEmpty(loanRepayDetailVO.getAmtType())) {
			String[] amtType = loanRepayDetailVO.getAmtType().split(",");
			for(int i=0; i<amtType.length; i++) {
				ReqLoanAccountBean reqLAccBean = new ReqLoanAccountBean();
				//金额类型
				reqLAccBean.setAmtType(amtType[i]);
				//结算金额
				BigDecimal setlAmt = BigDecimal.ZERO;
				if(EsbEnums.AmtType.ALL.getValue().equals(amtType[i])) {
					//本次还款总计金额
					setlAmt = loanRepayDetailVO.getTotalAmt();
				}else if(EsbEnums.AmtType.PRINCIPAL.getValue().equals(amtType[i])) {
					//提前还本金额
					setlAmt = loanRepayDetailVO.getSetlOdPrcpAmt();
				}else if(EsbEnums.AmtType.INTEREST.getValue().equals(amtType[i])) {
					//还款时总拖欠利息
					setlAmt = loanRepayDetailVO.getAllOdNormIntAmt();
				}else if(EsbEnums.AmtType.COMP_INTEREST.getValue().equals(amtType[i])) {
					//还款时总拖欠复利
					setlAmt = loanRepayDetailVO.getAllOdCommIntAmt();
				}else if(EsbEnums.AmtType.DEF_INTEREST.getValue().equals(amtType[i])) {
					//还款时总拖欠罚息
					setlAmt = loanRepayDetailVO.getAllOdIntAmt();
				}else if(EsbEnums.AmtType.FEE.getValue().equals(amtType[i])) {
					//归还费用总计
					setlAmt = loanRepayDetailVO.getTotalFee();
				}	
				reqLAccBean.setBlgAmt(setlAmt == null ? BigDecimal.ZERO.toString() : setlAmt.toString());

				//结算账户分类
				reqLAccBean.setBlgAcctCl(loanRepayDetailVO.getSetlAcctClassify());
				//结算方式  = 还款模式
				reqLAccBean.setBlgMth(loanRepayDetailVO.getSetlMode());
				//账户分类  = 账户类型
				reqLAccBean.setAcctCtgry(loanRepayDetailVO.getAcctTyp());
				//结算客户号
				reqLAccBean.setBlgCstNo(loanRepayDetailVO.getCusNo());
				//结算账号 = 还款账号
				reqLAccBean.setBlgAcctNo(loanRepayDetailVO.getDisbAcNo());
				//结算账户产品类型
				reqLAccBean.setBlgAcctProdType(loanRepayDetailVO.getSetlAcctPrdType());
				//结算账户币种
				try {
					reqLAccBean.setBlgAcctCurrCd(SDicToExternal.getExternalSysDicVal(SDicToExternalConstant.SYSID_IFP, SDicToExternalConstant.CUR_TYPE, loanRepayDetailVO.getSetlCurr()));
				} catch (Exception e) {
					logger.error("币种字典项类型转换异常！", e);
					throw new Exception("调用贷款回收接口组装请求报文时，出现币种字典项转换异常！");
				}
				//结算账户序号
				reqLAccBean.setBlgAcctSrlNo(loanRepayDetailVO.getSetlAcctSeq());
				//自动锁定标记
				reqLAccBean.setAtmLockMark(loanRepayDetailVO.getAtmLockMark());
				//贷款优先级
				reqLAccBean.setLoanPrtyLvl(loanRepayDetailVO.getLoanPrtyLvl());
				//结算权重
				reqLAccBean.setBlgRto(loanRepayDetailVO.getSetlWeight());
				//行内外标志
				reqLAccBean.setBankInsdOutSdFlg(loanRepayDetailVO.getBankInOut());
				//变更方式
				reqLAccBean.setMdfMd(loanRepayDetailVO.getModifyMode());

				reqLoanAccountList.add(reqLAccBean);
			}
		}
		//结算信息数组----------------- 组装 end ------------------------------------------------
		reqLoanRepayBean.setIntSetInfArry(reqLoanAccountList.toArray(new ReqLoanAccountBean[reqLoanAccountList.size()]));

		return reqLoanRepayBean;
	}


	private void excuteRepay(LoanRepayDetailVO loanRepayDetailVO, AccLoanVO accLoanVO) throws Exception {
		String setlSeq = loanRepayDetailVO.getSetlSeq();
		//  1. 调用贷款还款接口
		logger.info("调用贷款还款接口开始----------------------还款申请流水号：" + setlSeq);
		// 1.1组装贷款还款接口请求报文
		ReqLoanRepayBean reqLoanRepayBean = this.buildReqLoanRepayBean(loanRepayDetailVO, accLoanVO);
		// 1.2调用贷款还款接口
		RespLoanRepayBean respLoanRepayBean = new RespLoanRepayBean();
		try {
			respLoanRepayBean = loanRepayService.loanRepay(reqLoanRepayBean,loanRepayDetailVO);
		} catch (Exception e) {
			throw new ExternalSysException(e.getMessage());
		}
		logger.info("调用贷款还款接口结束----------------------还款申请流水号：" + setlSeq);

		String sysHeadRetCode = respLoanRepayBean.getSysHeadRetCode();
		if(EsbBizEnums.RetCodeEnum.SUCCESS.getVALUE().equals(sysHeadRetCode)){
			this.updStateAndLmt(loanRepayDetailVO, accLoanVO);
		}
		else if(EsbBizEnums.RetCodeEnum.FAILURE.getVALUE().equals(sysHeadRetCode)){
			throw new Exception("还款申请失败！--------还款申请流水号：" + setlSeq);
		}
		else if(EsbBizEnums.RetCodeEnum.REPEAT.getVALUE().equals(sysHeadRetCode)){
			throw new Exception("还款申请请求重复！--------还款申请流水号：" + setlSeq);
		}
		else if(EsbBizEnums.RetCodeEnum.HAND.getVALUE().equals(sysHeadRetCode)){
			throw new ExternalSysException("还款申请处理中！--------还款申请流水号：" + setlSeq);
		}
	}


	/**
	 * 还款成功后处理
	 * 	 1. 更新还款审批状态为“通过”
	 * 	 2. 更新授信协议信息
	 * @author  qiuyf
	 * @since 2019年5月14日 下午4:39:07
	 * @version 0.1 初始为0.1,后续变更则修改
	 */
	private void updStateAndLmt(LoanRepayDetailVO loanRepayDetailVO, AccLoanVO accLoanVO) throws OcmSystemException {
		String setlSeq = loanRepayDetailVO.getSetlSeq();
		logger.info("======>还款申请准入服务执行到还款成功后,后处理开始,流水号为:"+setlSeq+"<======");
		try {
			// 更新还款申请状态为“通过”
			loanRepayDetailVO.setWfApprSts(NlsApplyInfoEnums.NlsApplyState.PASS.getKey());
			/**
			 * mycat中不允许修改作为分库依据的列，所以更新的时候去掉“loan_no”
			 * 将更新执行的bean中loanNo字段赋值为null，更新语句会检测是否为空，再做更新。
			 * @date 2019/06/15
			 * @author qiuyf
			 * 
			 * 【2019/06/17，需求要求不使用mycat分片】
			 * loanRepayDetailVO.setLoanNo(null);
			 */
			int num = loanRepayDetailService.updateByPk(loanRepayDetailVO);

			if(num < 0) {
				logger.error("更新还款申请状态为“通过”，执行失败！");
				throw new OcmSystemException(SedNlsEnum.ExceptionLocation.REPAY_SUCCESS_AFTER_EXCEPTION.getValue(), "还款成功后，更新还款申请状态为“通过”，执行失败！--------还款申请流水号："+ setlSeq);
			}
			// 进行额度恢复（更新已用额度、可用额度）
			//获取授信申请流水号
			String lmtApplySeq = this.getLmtApplySeq(accLoanVO.getApplySeq());
			//获取授信协议信息
			LmtPrdContVO lmtPrdContVO = lmtPrdContService.qryLmtPrdContByLmtApplySeq(lmtApplySeq);
			if(Objects.nonNull(lmtPrdContVO)) { 
				BigDecimal lmtAmt = lmtPrdContVO.getLmtAmt();
				BigDecimal occAmt = lmtPrdContVO.getOccAmt().toString() == null ? BigDecimal.ZERO : lmtPrdContVO.getOccAmt();
				BigDecimal preOccAmt = lmtPrdContVO.getPreOccAmt() == null ? BigDecimal.ZERO : lmtPrdContVO.getPreOccAmt();
				BigDecimal rpyPrin = loanRepayDetailVO.getSetlOdPrcpAmt();

				//已用额度 = 原已用额度  - 还款本金 
				lmtPrdContVO.setOccAmt(occAmt.subtract(rpyPrin));
				//可用额度  = 授信额度 - 已用额度 - 预占用额度  + 还款本金 
				lmtPrdContVO.setAvailAmt(lmtAmt.subtract(occAmt).subtract(preOccAmt).add(rpyPrin));
				//最近更新时间
				lmtPrdContVO.setLastUpdateTime(TimeUtil.getCurrentDateTime());

				int numLmt = lmtPrdContService.updateByPk(lmtPrdContVO);

				if(numLmt < 0) {
					throw new OcmSystemException(SedNlsEnum.ExceptionLocation.REPAY_SUCCESS_AFTER_EXCEPTION.getValue(),
							"还款成功后，更新授信协议信息失败！还款申请流水号【" + setlSeq + "】，授信申请流水号：" + lmtApplySeq);
				}
			}else {
				logger.error("还款成功后，进行额度恢复，通过授信申请流水号【" + lmtApplySeq + "】，获取到的授信协议信息为空！");
				throw new OcmSystemException(SedNlsEnum.ExceptionLocation.REPAY_SUCCESS_AFTER_EXCEPTION.getValue(),
						"通过授信申请流水号【 " + lmtApplySeq + "】，查询到的授信协议信息为空！还款申请流水号：" + setlSeq);
			}
		} catch (Exception e) {
			throw new OcmSystemException(e);
		} finally {
			logger.info("======>还款申请准入服务执行到还款成功后,后处理结束,流水号为:"+setlSeq+"<======");
		}
	}
	
	/**
	 * 通过支用申请流水号查询授信申请流水号
	 * @author  qiuyf
	 * @since 2019年6月27日 下午8:05:51
	 * @version 0.1 初始为0.1,后续变更则修改
	 */
	private String getLmtApplySeq(String applySeq) throws OcmSystemException {
		NlsApplyInfoVO nlsApplyInfoVO = new NlsApplyInfoVO();
		nlsApplyInfoVO.setApplySeq(applySeq);
		nlsApplyInfoVO = nlsApplyInfoService.queryByPk(nlsApplyInfoVO);
		if(Objects.isNull(nlsApplyInfoVO)) {
			throw new OcmSystemException("还款成功后更新授信协议信息时，通过支用申请流水号【" + applySeq + "】，获取到的支用信息为空！");
		}
		if(StringUtil.isNullorBank(nlsApplyInfoVO.getLmtApplySeq())) {
			throw new OcmSystemException("还款成功后更新授信协议信息时，通过支用申请流水号【" + applySeq + "】，获取到的授信申请流水号为空！");
		}
		return nlsApplyInfoVO.getLmtApplySeq();
	}
	

	@Autowired
	@Qualifier("loanRepayResultQryService")
	private LoanRepayResultQryService loanRepayResultQryService;

	@Autowired
	@Qualifier("accLoanService")
	private AccLoanService accLoanService;

	@Autowired
	@Qualifier("loanRepayService")
	private LoanRepayService loanRepayService;

	@Autowired
	@Qualifier("loanRepayDetailService")
	private LoanRepayDetailService loanRepayDetailService;

	@Autowired
	@Qualifier("nlsApplyInfoService")
	private NlsApplyInfoService nlsApplyInfoService;
	
	@Autowired
	@Qualifier("lmtPrdContService")
	private LmtPrdContService lmtPrdContService;

}
